home *** CD-ROM | disk | FTP | other *** search
- /********************************************************************
- * lindner
- * 3.5
- * 1993/04/15 21:35:12
- * /home/mudhoney/GopherSrc/CVS/gopher+/object/GDgopherdir.c,v
- * Exp
- *
- * Paul Lindner, University of Minnesota CIS.
- *
- * Copyright 1991, 1992 by the Regents of the University of Minnesota
- * see the file "Copyright" in the distribution for conditions of use.
- *********************************************************************
- * MODULE: GDgopherdir.c
- * Implement gopher directory routines
- *********************************************************************
- * Revision History:
- * GDgopherdir.c,v
- * Revision 3.5 1993/04/15 21:35:12 lindner
- * Debug code, better .Link processing, better GDfromNet()
- *
- * Revision 3.4 1993/03/26 19:50:44 lindner
- * Mitra fixes for better/clearer fromNet code
- *
- * Revision 3.3 1993/03/24 17:04:49 lindner
- * bad strcmp() can check unmalloced() mem, fixed
- *
- * Revision 3.2 1993/03/18 22:13:29 lindner
- * filtering, compression fixes
- *
- * Revision 3.1 1993/02/11 18:03:01 lindner
- * Initial revision
- *
- * Revision 2.1 1993/02/09 22:46:50 lindner
- * Many additions for gopher+
- *
- * Revision 1.4 1993/01/31 00:22:51 lindner
- * Changed GDaddGS to merge entries with the same path.
- * Added GDplusfromNet() to siphon data from network.
- * GDfromLink now knows about ~/ inside of Path=
- * Changed GDSearch to ignore leading character.
- *
- * Revision 1.3 1992/12/19 04:44:09 lindner
- * Added GDplustoNet()
- *
- * Revision 1.2 1992/12/16 20:37:04 lindner
- * Added function GDsearch(), does a linear search of a gopher directory
- *
- * Revision 1.1 1992/12/10 23:27:52 lindner
- * gopher 1.1 release
- *
- *
- *********************************************************************/
-
-
- #include "GDgopherdir.h"
- #include "Malloc.h"
-
-
- #include <string.h>
- #include <stdio.h>
- extern int DEBUG;
-
-
- /***********************************************************************
- ** Stuff for GopherDirObjs
- **
- ***********************************************************************/
-
-
- GopherDirObj*
- GDnew(size)
- int size;
- {
- int i;
- GopherDirObj *temp;
-
- temp = (GopherDirObj*) malloc(sizeof(GopherDirObj));
-
- temp->Gophers = DAnew(size, GSnew, GSinit, GSdestroy, GScpy);
-
- temp->Title = STRnew();
- temp->currentitem = 1;
-
- GDinit(temp);
- return(temp);
- }
-
-
- void
- GDdestroy(gd)
- GopherDirObj *gd;
- {
- int i;
-
- DAdestroy(gd->Gophers);
-
- STRdestroy(gd->Title);
- free(gd);
- }
-
-
- void
- GDinit(gd)
- GopherDirObj *gd;
- {
- int i;
-
- DAinit(gd->Gophers);
- STRinit(gd->Title);
- }
-
-
- extern int DEBUG;
-
- /** This proc adds a GopherObj to a gopherdir.
- It will attempt to merge two items if need be..
- **/
- void
- GDaddGSmerge(gd, gs)
- GopherDirObj *gd;
- GopherObj *gs;
- {
- int num;
-
- num = GDSearch(gd, GSgetPath(gs));
-
- if (num == -1)
- DApush(gd->Gophers, gs);
- else {
- GSmerge(GDgetEntry(gd, num),gs);
- }
- }
-
-
- /*
- * This one never tries to merge
- */
-
- void
- GDaddGS(gd, gs)
- GopherDirObj *gd;
- GopherObj *gs;
- {
- int num;
-
- if (GSgetType(gs) != 'X')
- DApush(gd->Gophers, gs);
- }
-
-
- /*
- * Really weird!!! We need this for qsort, don't know why we can't use
- * GScmp...
- */
-
- int
- GSqsortcmp(gs1, gs2)
- GopherObj **gs1, **gs2;
- {
- if (GSgetTitle(*gs1) == NULL)
- return(1);
- if (GSgetTitle(*gs2) == NULL)
- return(-1);
-
- /** No numbering set on either entry, or both numbered
- entries have the same number **/
-
- if (GSgetNum(*gs1) == GSgetNum(*gs2))
- return(strcmp(GSgetTitle(*gs1), GSgetTitle(*gs2)));
-
- /** first one numbered, second not **/
- if (GSgetNum(*gs1) != -1 && GSgetNum(*gs2) == -1)
- return(-1);
-
- /** second one numbered, first not **/
- if (GSgetNum(*gs1) == -1 && GSgetNum(*gs2) != -1)
- return(1);
-
- /** Both numbered, integer compare them **/
-
- return(GSgetNum(*gs1) - GSgetNum(*gs2));
- }
-
- /*
- * Sorts a gopher directory
- */
-
- void
- GDsort(gd)
- GopherDirObj *gd;
- {
-
- DAsort(gd->Gophers, GSqsortcmp);
- }
-
-
- void
- GDtoNet(gd, sockfd)
- GopherDirObj *gd;
- int sockfd;
- {
- int i;
- if (DEBUG) fprintf (stderr, "GDplustoNet\n");
- for (i=0; i< GDgetNumitems(gd); i++) {
- GStoNet(GDgetEntry(gd, i), sockfd);
- }
-
- }
-
-
- void
- GDplustoNet(gd, sockfd, filter)
- GopherDirObj *gd;
- int sockfd;
- char **filter;
- {
- int i;
-
- for (i=0; i< GDgetNumitems(gd); i++) {
- GSplustoNet(GDgetEntry(gd, i), sockfd,filter);
- }
- }
-
- void
- GDtoNetHTML(gd, sockfd)
- GopherDirObj *gd;
- int sockfd;
- {
- int i;
-
- writestring(sockfd, "<MENU>\r\n");
-
- for (i=0; i< GDgetNumitems(gd); i++) {
- writestring(sockfd, "<LI>");
- GStoNetHTML(GDgetEntry(gd, i), sockfd);
- }
- writestring(sockfd, "</MENU>");
- }
-
- /*
- * Gopher+ counterpart to GDfromNet()
- */
-
-
- #define DODEBUG(loc) if (DEBUG) { fprintf(stderr,"GDplusfromNet:%s;\n",loc);}
-
- int
- GDplusfromNet(gd, fd, eachitem)
- GopherDirObj *gd;
- int fd;
- int (*eachitem)();
- {
- static GopherObj *TempGopher;
- static char ZesTmp[1024];
- int j, result;
- char inputline[256];
-
- DODEBUG("start")
- if (TempGopher == NULL)
- TempGopher = GSnew();
-
- /** State: _begin_ **/
-
- result = readrecvbuf(fd, inputline, 1);
- if (result <=0 || *inputline != '+')
- return(0);
-
- DODEBUG("after readrecvbuf")
- /** State _FirstPlus_ **/
-
- result = readtotoken(fd, inputline, sizeof(inputline), ':');
- if (result <=0)
- return(result);
-
- DODEBUG("after readtotoken")
- if (strcmp(inputline, "INFO")!=0) {
- return(0);
- }
- DODEBUG("after INFO")
- /** Read the space **/
- readrecvbuf(fd, inputline, 1);
-
-
- /*** State _FirstINFO_ ***/
-
- for (j=0; ; j++) {
-
- DODEBUG("for start")
- ZesTmp[0] = '\0';
-
- GSinit(TempGopher);
- result = GSplusfromNet(TempGopher, fd);
-
- switch (result) {
- case MORECOMING:
- GDaddGS(gd, TempGopher);
- if (eachitem != NULL)
- eachitem();
- break;
-
- case FOUNDEOF:
- GDaddGS(gd, TempGopher);
- return(j+1);
-
- case HARDERROR: /** Give up reading - bad read or protocol error **/
- return(j);
-
- case SOFTERROR: /** This one was bad, but we can try for next **/
- j= j-1;
- if (j<0) j=0;
- break;
- }
-
- } /* for */
-
- /** Never get here **/
- }
-
- /*
- * Fill up a GopherDirObj with GopherObjs, given a gopher directory coming
- * from sockfd.
- *
- * For each GopherObj retrieved, eachitem() is executed.
- *
- */
-
- void
- GDfromNet(gd, sockfd, eachitem)
- GopherDirObj *gd;
- int sockfd;
- int (*eachitem)();
- {
- static GopherObj *TempGopher;
- static char ZesTmp[1024];
- int i;
-
- if (DEBUG) fprintf(stderr, "GDfromNet...");
- if (TempGopher == NULL)
- TempGopher = GSnew();
-
- for (; ;) {
-
- ZesTmp[0] = '\0';
-
- GSinit(TempGopher);
- i = GSfromNet(TempGopher, sockfd);
-
- /* In gopher+1.2b2 this routine clears up if GSfromNet returns
- a failure, better to clear up in GSfromNet so that the
- system returns in a known state - note that other callers of
- GSfromNet didn't clean up and crashed! */
-
- switch (i) {
-
- case 0:
- GDaddGS(gd, TempGopher);
- if (eachitem != NULL) eachitem();
- break;
-
- case 1: /* . on a line by itself, nothing more */
- return;
-
- case SOFTERROR: /** Unknown object type **/
- break;
-
- case HARDERROR:
- return;
- }
- }
- }
-
-
- /*
- * Given an open file descriptor and an inited GopherDirobj,
- * read in gopher links, and add them to a gopherdir
- */
-
- void
- GDfromLink(gd, fd, host, port, directory)
- GopherDirObj *gd;
- int fd;
- char *host;
- int port;
- char *directory;
- {
- GopherObj *gs;
- char testline[512];
- int num;
- int result;
-
- gs = GSnew();
-
-
- while (1) {
- result = GSfromLink(gs, fd, host, port,directory);
-
- if (result == HARDERROR)
- break;
- if (result == SOFTERROR)
- continue;
-
- if (*GSgetPath(gs) == '.')
- GDaddGSmerge(gd, gs);
- else
- GDaddGS(gd, gs);
-
- if (result == FOUNDEOF)
- break;
-
- GSinit(gs);
- }
-
- GSdestroy(gs);
- }
-
-
- void
- GDtoLink(gd, fd)
- GopherDirObj *gd;
- int fd;
- {
- int i;
-
- for (i=0; i< GDgetNumitems(gd); i++) {
- GStoLink(GDgetEntry(gd, i), fd);
- }
-
- }
-
- /*** Search for a specific gopher item ***/
- /* Allow text to end in .Z - gd will never have a .Z item in it due to fix
- in gopherd/gopherd */
- int
- GDSearch(gd, text)
- GopherDirObj *gd;
- char *text;
- {
- int i;
- int WasCtrlZ = 0;
- GopherObj *gs;
- int len;
-
- if (gd == NULL)
- return(-1);
-
- if (text == NULL)
- return(-1);
-
- len = strlen(text);
- if (len >2) {
- WasCtrlZ = (strcmp(text+strlen(text)-2,".Z") == 0);
- if (WasCtrlZ)
- text[strlen(text)-2] = '\0';
- }
-
- for (i=0; i< GDgetNumitems(gd); i++) {
- gs = GDgetEntry(gd, i);
-
- if (len >1 && strcmp(text+1, GSgetPath(gs)+1) == 0) {
- if (WasCtrlZ)
- text[strlen(text)-2] = '.';
- if (DEBUG) fprintf (stderr, "Matched\n");
- return(i);
- }
- }
- if (WasCtrlZ)
- text[strlen(text)-2] = '.';
- if (DEBUG) fprintf (stderr, "No Match\n");
- return(-1);
- }
-
-